/**
 * 
 */
package gui.views;

import gui.LibraryComboBox;
import gui.OperatorList;
import gui.TypeList;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.regex.Pattern;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import libraries.Library;
import metagrammar.Operator;
import util.OperatorWrapper;
import application.Application;
import application.GlobalContext;

/**
 * @author Joshua Lockerman
 *
 */
public class CreateLibraryView extends JFrame {
    
    private final GlobalContext context;
    
    private JTextField nameField;
    
    private DefaultListModel<metagrammar.Type> types;
    
    private DefaultListModel<OperatorWrapper> operators;
    
    public CreateLibraryView()
    {
        super("Create Library");
        context = Application.injector.getInstance(GlobalContext.class);
        
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLayout(new BorderLayout());
        
        add(createLibraryPanel(), BorderLayout.CENTER);
        
        add(createSelectorPanel(), BorderLayout.WEST);
        
        add(createButtonPanel(), BorderLayout.SOUTH);
        pack();
        setMinimumSize(getSize());
    }
    
    private Component createSelectorPanel()
    {
        JPanel panel = new JPanel(new BorderLayout());
        
        LibraryComboBox lib = new LibraryComboBox();
        panel.add(lib, BorderLayout.NORTH);
        
        final TypeList typeSelector = lib.createTypeList();
        final OperatorList opSelector = lib.createOperatorList();
        
        typeSelector.setBorder(BorderFactory.createTitledBorder("Types"));
        opSelector.setBorder(BorderFactory.createTitledBorder("Operators"));
        
        JPanel selectPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
        panel.add(selectPanel, BorderLayout.CENTER);
        selectPanel.add(new JScrollPane(typeSelector));
        selectPanel.add(new JScrollPane(opSelector));
        
        typeSelector.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
                    types.addElement(typeSelector.getSelectedValue());
                }
            }
        });
        
        opSelector.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
                    operators.addElement(opSelector.getSelectedValue());
                }
            }
        });
        
        return panel;
    }
    
    private Component createLibraryPanel()
    {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("New Library"));
        
        nameField = new JTextField(20);
        nameField.setBorder(BorderFactory.createTitledBorder("Name"));
        panel.add(nameField, BorderLayout.NORTH);
        
        
        JPanel libComponents = new JPanel();
        libComponents.setLayout(new BoxLayout(libComponents, BoxLayout.X_AXIS));
        
        types = new DefaultListModel<metagrammar.Type>();
        JList<metagrammar.Type> typeList = new JList<metagrammar.Type>(types);
        typeList.setPrototypeCellValue(metagrammar.Type.UNTYPED);
        typeList.setBorder(BorderFactory.createTitledBorder("Types"));
        typeList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        JScrollPane typeScroll = new JScrollPane(typeList);
        libComponents.add(typeScroll);
        
        operators = new DefaultListModel<OperatorWrapper>();
        JList<OperatorWrapper> operatorList = new JList<OperatorWrapper>(operators);
        operatorList.setBorder(BorderFactory.createTitledBorder("Operators"));
        operatorList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        operatorList.setPrototypeCellValue(new OperatorWrapper(Operator.undefinedOperator));
        JScrollPane operatorScroll = new JScrollPane(operatorList);
        libComponents.add(operatorScroll);
        
        panel.add(libComponents, BorderLayout.CENTER);
        
        return panel;
    }
    
    private JPanel createButtonPanel()
    {
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING));
        
        JButton okButton = new JButton();
        okButton.setAction(new AbstractAction("Create") {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                createLibrary();
            }
        });
        buttonPanel.add(okButton);
        
        JButton cancelButton = new JButton();
        cancelButton.setAction(new AbstractAction("Cancel") {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                dispose();
            }
        });
        buttonPanel.add(cancelButton);
        return buttonPanel;
    }
    
    public void createLibrary()
    {
        if(nameField.getText().length() == 0) {
            JOptionPane.showMessageDialog(this, "The name of the new Library cannot be empty.",
                    "Library creation error.", JOptionPane.ERROR_MESSAGE);
            return;
        }
        String text = nameField.getText();
        if(Pattern.compile("(\\)(/)(\n)(:)(*)(?)(<)(>)(|)").matcher(text).find()) {
            JOptionPane.showMessageDialog(this,
                            "The name of the new Library cannot contain any of \\ / : * ? < > | or newLines",
                    "Library creation error.", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        HashSet<Operator> opSet = new HashSet<Operator>(operators.size());
        for(int i = 0; i < operators.getSize(); i++) {
            opSet.add(operators.get(i).getOperator());
        }
        HashSet<metagrammar.Type> typeSet = new HashSet<metagrammar.Type>(types.size());
        for(int i = 0; i < types.getSize(); i++) {
            typeSet.add(types.get(i));
        }
        
        Library lib = new Library(nameField.getText(), typeSet, opSet);
        context.add(lib);
        JOptionPane.showMessageDialog(this, "Library " + lib + " added.");
        dispose();
    }
}
